$(function() {

    console.log("投稿フォーム画面の初期化を開始します。");

    // ログイン情報を保持
    var account = Account.getLoginInfo();
    
    console.log("アカウント情報=" + JSON.stringify(account));

    // タイムライン表示件数を保持
    var dispCount = localStorage["shovel.dispCount"]||DEF_DISP_COUNT;

    // タイムライン更新頻度を保持
    var updateInterval = localStorage["shovel.interval"]||DEF_UPD_INTERVAL;

    // フォロワ一覧の初期化フラグ
    var isInitFollowers = false;

    // 補完フラグ
    var isCompletion = false;

    // 補完候補文字
    var completion = "";

    /*******************************************************************
     * リプライユーザ匿名クラスインスタンス
     *******************************************************************/
    var replyers = function() {

        // フォロワーの一覧
        var followers = {};
        
        // フォロワークラス
        var Follower = function (screen_name, name) {

            /* public ユーザID */
            this.screenName = screen_name;

            /* public ユーザ表示名 */
            this.name = name;

            // 表示名がなければ"表示名:=ユーザID"
            if (!name) this.name = screen_name;
        };

        // リプライユーザーコンボの初期化処理
        var setUsers = function(responseXML) {
        
            // userタグをすべて抽出
            var $users = $("user", responseXML);

            console.log("フォロワー数=" + $users.size());

            // userタグがなければ終了
            if ($users.size() <= 0) {
                isInitFollowers = true;
                return null;
            }

            // 補完リストを初期化
            var $compList = $("#followers");
            $compList.attr("size", $users.size() > 8? 8: $users.size()).html("");

            // ユーザ要素から名称を取得してコンボボックスに追加
            var addFollower = function(idx, $user) {
                var screen_name = $("screen_name:first", $user).text();
                if (!screen_name) return;
                console.log("フォロワー" + idx + ":" + screen_name);
                var follower = new Follower(screen_name, $("name:first", $user).text());
                $compList.append($("<OPTION>").attr("value", follower.screenName).text(follower.name));
                followers[follower.screenName] = follower.name; // 変数にも格納しておく
            }

            $users.each(addFollower);
            
            console.log("フォロワーリスト=" + JSON.stringify(followers));

            isInitFollowers = true;
        };

        return {
            // フォロワーの一覧を取得してリプライユーザーコンボを初期化する
            init: function() {
                if (!account) return;
                // XmlHttpRequestでPOSTデータを送信
                Ajax.send(
                      "/statuses/followers.xml"
                    , {}
                    , {"id": account.userName}
                    , setUsers
                );
            },
            // ユーザ名から表示名を取得する
            getUserName: function (name) {
                var anchor = "<a class='reply' href='http://" + HOSTNAME + "/" + name + "' target='_blank'>$name</a>";
                if (account && name == account.userName) return anchor.replace(/\$name/, "あなた");
                return anchor.replace(/\$name/, (followers[name]||name)) + "さん";
            },
            // フォロワーリストをモードレス表示する
            showFollowerList: function(char) {
                // TODO インクリメンタル絞り込みは未実装
                if (char) {
                    console.log("インクリメンタル絞り込み実装予定");
                    return false;
                }
                var top = $("#text").css("height").match(/\d+/);
                $("#followers").css("top", top).fadeIn("fast");
            }
        }
    }();

    /*******************************************************************
     * タイムラインの内容を変換する匿名クラスインスタンス
     *******************************************************************/
    var converter = function () {

        // リプライタグ(@XXX)にマッチするパターン
        var REPLY_TAG = /^@(\w+)(?=\s)|\s@(\w+)(?=\s)|\s@(\w+)$/g;

        // URLにマッチする正規表現
        var URL = /((?:https?|ftp):\/\/[0-9a-zA-Z,;:~&=@_'%?+\/\$.!*()\-]+)/g;   // 'ダミーコメント

        // メールアドレス(RF2822準拠)にマッチする正規表現
        var MAIL = /((?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+))*)|(?:"(?:\\[^\r\n]|[^\\"])*")))\@(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+))*)|(?:\[(?:\\\S|[\x21-\x5a\x5e-\x7e])*\]))))/g; // "ダミーコメント
        
        // "リプライタグをユーザ名に変換して返す
        var createHeader = function(text) {
            // リプライ対象ユーザ名を取得
            var reply = null;
            var replies = [];
            while ( (reply = REPLY_TAG.exec(text)) != null) {
                // ユーザIDから表示名を取得
                var username = replyers.getUserName(reply[1]||reply[2]||reply[3]);
                replies.push(username);
            }
            // リプライタグがなければ空文字を返す
            if (replies.length <= 0) return "";
            return "<span class='reply'>" + replies.join(",") + "への返信</span>";
        };

        // URLをリンクに変換し、メールアドレスをGMailリンクに変換して返す
        var createBody = function(text) {
            var body = text.trim().replace(REPLY_TAG, "");
            body = convertUrlLink(body);
            body = convertEMailLink(body);
            return body;
        };

        // URLをアンカーに変換する
        var convertUrlLink = function(text) {
            return text.replace(URL, "<a href='$1' target='_blank'>$1</a>");
        };

        // メールアドレスをアンカーに変換する
        var convertEMailLink = function(text) {
            return text.replace(MAIL, "<a href='https://mail.google.com/mail/?view=cm&fs=1&to=$1' target='_blank'>$1</a>");
        };

        return {
            execute: function(text) {
                return createHeader(text) + createBody(text);
            }
        }
    }();

    /*******************************************************************
     * タイムラインを更新する匿名クラスインスタンス
     *******************************************************************/
    var timeline = function () {

        // XMLタグからタイムラインを１件取得し、TRタグを生成して返す
        var createData = function(status) {
        
            // ユーザ名をuserタグから取得する
            var $user = $("user:first", status);
            var $userName = $("name:first", $user).text();
            
            // nameがなければscreen_name
            if(!$userName) $userName = $("screen_name:first", $user).text();

            // 投稿日時 
            var created_at = new Date($("created_at", status).text());

            // 最終投稿日時を更新
            var lastUpdate = new Date(localStorage["shovel.lastUpdate"]||new Date(0));
            if (!lastUpdate || lastUpdate.getTime() < created_at.getTime()) {
                localStorage["shovel.lastUpdate"] = created_at;
            }

            // 文字列に変換 (yyyy/M/d H:mm:ss)
            created_at = created_at.formatJa();
            if (created_at.startsWith(today)) {
                created_at = created_at.substring(today.length+1);
            } else {
                created_at = created_at.substring(0, created_at.lastIndexOf(":"));
            }

            // 投稿内容を取得
            var text = ($("text:first", status).text()||"")
                .replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\r?\n/g, "<br/>");

            console.log(created_at + ": " + text);

            // 投稿内容を見やすく加工
            text = converter.execute(text);

            // TDタグを生成
            var $col = $("<TD/>")
                .addClass("timeline_col")
                .html("<span class='userName'>" + $userName + ":</span> "
                    + text + "<span class='time'>(" + created_at + ")</span>");

            // TRタグを生成
            return $("<TR/>").append($col);
        };

        // タイムラインに行を追加する
        var setTableData = function (responseXML) {

            // バッジをクリア
            chrome.browserAction.setBadgeText({text:""});
        
            // statusタグをすべて抽出
            var $statuses = $("status", responseXML);

            console.log("タイムライン数=" + $statuses.size());
            
            // statusタグがなければ終了
            if ($statuses.size() <= 0) return;

            var $timeline = $("#timeline").html("");

            var l = dispCount < $statuses.size() ? dispCount: $statuses.size();

            console.log("表示件数=" + l);
            
            for (var i=0; i<l; i++) {
                var $rowData = createData($statuses[i]);
                if ($rowData) $timeline.append($rowData);
            }
        };

        return {
            update: function () {
            
                if (!account) return;
                
                Ajax.send(
                      "/statuses/friends_timeline.xml"
                    , {}
                    , {"count": dispCount}
                    , setTableData
                );
            }
        }
    }();

    // アンカータグのhrefを無効化
    $("#insert,#post").attr("href", "JavaScript:void(0)");

    // 投稿メッセージの編集イベント。残り文字数表示を更新する。
    $("#text").bind("keyup", function (e) {
        var val = $(this).val();
        var num = 140;
        var bgColor = "#FFFFFF";
        if (!val) {
            num -= val.length;
            bgColor = "#FFFFD0";
        }
        $("#restlength")
            .css("background-color", bgColor)
            .css("color", (num < 0) ? "red": "black")
            .html(num);

        // リプライユーザ補完処理

        // @が押されたら補完リスト表示
        if (e.keyCode == 192) {
            isCompletion = true;
            completion = "";
            replyers.showFollowerList();
        }
/*
        // a～z が押されたらインクリメンタルで絞込み(未実装)
        else if (e.keyCode > 64 && e.keyCode < 91) {
            replyers.showFollowerList(String.fromCharCode(e.keyCode));
        }
        // ↑キーが押されたら１つ上のフォロワを選択
        else if (isCompletion && e.keyCode == 38) {
            console.log("selectedIndex=" + $("#followers").selectedIndex);
            var selectedIndex = parseInt($("#followers").selectedIndex||0);
            if (selectedIndex == 0) selectedIndex = -1;
            $("#followers").attr("selectedIndex", selectedIndex++);
        }
        // ↓キーが押されたら１つ下のフォロワを選択
        else if (isCompletion && e.keyCode == 40) {
            console.log("selectedIndex=" + $("#followers").selectedIndex);
            var selectedIndex = parseInt($("#followers").selectedIndex||0);
            if (selectedIndex == $("#followers").children().size()-1) {
                selectedIndex = $("#followers").children().size();
            }
            $("#followers").attr("selectedIndex", selectedIndex--);
        }
*/
        // それ以外は補完リストを非表示
        else {
            if (isCompletion) {
                isCompletion = false;
                $("#followers").fadeOut("fast");
            }
        }
        
    });

    // 投稿リンクイベント。メッセージを投稿する。
    $("#post").bind("click", function() {

        if (!account) {
            Message.print("ログイン情報が設定されていません。");
            return;
        }
        
        var text = $("#text").val();

        var validate = function (text) {
            var errors = [];
        
            // 必須入力チェック
            if (!text || !text.length || text.length < 1) {
                errors.push("投稿するメッセージを入力してください。");
            }
            
            // 最大桁数チェック
            if (text.length > 140) {
                errors.push("140文字以内で入力してください。");
            }

            if (errors.length <= 0) {return true;}
            
            Message.print(errors.join("<br/>"), "red", 5000);
            $("#text").focus();
            return false;
        }
        if (!validate(text)) { return false; }

        // XmlHttpRequestでPOSTデータを送信
        Ajax.send(
              "/statuses/update.xml"
            , {
                  "X-Twitter-Client": "shovel-extension"
                , "X-Twitter-Client-Version": "2.1"
                , "X-Twitter-Client-URL": "http://" + HOSTNAME + "/"
              }
            , {"status": text, "source": "shovel-extension"}
            , function() {
                    Message.print("メッセージを投稿しました。", "blue");
                    $("#text").val("").html("").keyup();
                    timeline.update();
              }
            , function(ajax, textStatus, errorThrown) {
                    if (ajax.status == 401) {
                        Message.print("ログイン情報に誤りがあります。");
                        return;
                    }
                    Message.print("投稿できません。\n" + ajax.status + " " + ajax.statusText, "red");
              }
        );
    });

    // 挿入リンクイベント。選択されたリプライユーザ名をテキストに挿入する。
    $("#insert").bind("click", function() {
        var userId = $("#userlist").children(":selected").val();
        if (!userId) return;
        if ($("#text").val()) { text.value += " @" + userId; }
        else { text.value = "@" + userId; }
        $("#text").keyup();
    });

    // フォロワー補完リスト選択イベント
    $("#followers").bind("change", function() {
        var val = $(this).val();
        if (val) {
            val = $("#text").val() + val + " ";
            $("#text").val("").focus().val(val);
        }
        isCompletion = false;
        /*
        completion = "";
        */
        // 選択解除
        $(this).fadeOut("fast").children(":selected").attr("selected", false);
    });

    // 一定間隔でタイムラインを自動更新
    var timer1 = setInterval(timeline.update, updateInterval);

    // コンボボックスとタイムラインを別スレッドで初期化
    setTimeout(replyers.init, 0);
    setTimeout(function() {
        // フォロワ一覧が未生成ならWait
        if (!isInitFollowers) {
            setTimeout(timeline.update, 10);
            return;
        }
        timeline.update();
    }, 500);

});
